#include "Sort.h"
#include "../SQLInterface/Tuple.h"
#include "../SQLInterface/Database.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#define MAX_CONSECUTIVE_TOKENS  5

void mergeSort(node_t** arrayToSort, node_t** buffer, int start, int end);
int tupleComparator (const void *, const void *);
inline int getDateVal(node_t* node);

int sortStockDataByDate(node_t** list)
{
    int listLength = 0;
    int i = 0;
    node_t* iterator;
    node_t** buffer;
    node_t** arrayToSort; // TODO: actually make this array of the tuples?

    for(iterator = *list; iterator != NULL; iterator = iterator->next)
    {
        // we actually just go ahead and use TableId to store the date conversion
        // integer for easier comparsions.
        ((tuple_t*)(iterator->element))->table = (TableID)dateToInt((char*)((tuple_t*)(iterator->element))->params[STOCK_DATA_PARAM_DATE]);
        listLength++;
    }

    // easier than using a sort on the linked list itself
    arrayToSort = (node_t**)malloc(listLength * sizeof(node_t*));
    buffer = (node_t**)malloc(listLength * sizeof(node_t*));

    // TODO: make this a smarter part of the actual sorting?
    for(iterator = *list; iterator != NULL; iterator = iterator->next)
    {
        arrayToSort[i++] = iterator;
    }

    // merge sort
    mergeSort(arrayToSort, buffer, 0, listLength-1);

    //qsort
    // THIS IS BUGGED WHEN I COMPILE!!......
    //qsort(arrayToSort, listLength, sizeof(tuple_t*), tupleComparator);

    // rebuild list
    *list = arrayToSort[0];
    for(i = 0; i < (listLength - 1); i++)
    {
        ((tuple_t*)(arrayToSort[i]->element))->table = TABLE_STOCK_DATA;
        arrayToSort[i]->next = arrayToSort[i + 1];
    }
    ((tuple_t*)(arrayToSort[listLength - 1]->element))->table = TABLE_STOCK_DATA;
    arrayToSort[listLength - 1]->next = NULL;

    free(arrayToSort);
    free(buffer);

    return listLength;
}

int tupleComparator (const void * elem1, const void * elem2)
{

    // do it backwards to get from greatest (most recent) to least (least recent)...
    return ((int)((tuple_t*)elem2)->table) - (int)(((tuple_t*)elem1)->table);
}


void mergeSort(node_t** arrayToSort, node_t** buffer, int start, int end)
{
    int endOfStart = (start + end) / 2;
    int startOfEnd = endOfStart + 1;
    int bufIndex = start;
    int i = start;

    if(end > start)
    {
        // recursion
        mergeSort(arrayToSort, buffer, start, endOfStart);
        mergeSort(arrayToSort, buffer, startOfEnd, end);

        // sort sorted arrays
        while((start <= endOfStart) && (startOfEnd <= end))
        {
            if(getDateVal(arrayToSort[start]) >= getDateVal(arrayToSort[startOfEnd]))
            {
                buffer[bufIndex++] = arrayToSort[start++];
            }
            else
            {
                buffer[bufIndex++] = arrayToSort[startOfEnd++];
            }
        }

        // fill in leftovers
        if(start <= endOfStart)
        {
            while(start <= endOfStart)
            {
                buffer[bufIndex++] = arrayToSort[start++];
            }
        }
        else
        {
            while(startOfEnd <= end)
            {
                buffer[bufIndex++] = arrayToSort[startOfEnd++];
            }
        }

        // set i correctly at beginning
        for(; i <= end; i++)
        {
            arrayToSort[i] = buffer[i];
        }
    }
}

// too lazy to type this alot...
inline int getDateVal(node_t* node)
{
    return ((tuple_t*)(node->element))->table;
}

int dateToInt(const char* const date)
{
    char buffer[11];
    int returnVal = 0;

    strcpy(buffer, date);

    returnVal += atoi(strtok(buffer,"-")) * 400; 
    returnVal += (atoi(strtok(NULL,"-")) - 1) * 31;
    returnVal += atoi(strtok(NULL,"-"));

    return returnVal;
}

char* webDateToSqlDate(const char* const date)
{
    char buffer[100]; //#define?
    char* token;
    char* returnVal = (char*)malloc(sizeof(char) * 11);//XXXX-XX-XX + null term
    int tryCount = 0;
    char month[3];
    char day[3];
    int dayNum;

    strcpy(buffer, date);

    token = strtok(buffer," ,");

    //get month
    if(strcmp(token, "Jan") == 0)
    {
        strcpy(month, "01");
    }
    else if(strcmp(token, "Feb") == 0)
    {
        strcpy(month, "02");
    }
    else if(strcmp(token, "Mar") == 0)
    {
        strcpy(month, "03");
    }
    else if(strcmp(token, "Apr") == 0)
    {
        strcpy(month, "04");
    }
    else if(strcmp(token, "May") == 0)
    {
        strcpy(month, "05");
    }
    else if(strcmp(token, "Jun") == 0)
    {
        strcpy(month, "06");
    }
    else if(strcmp(token, "Jul") == 0)
    {
        strcpy(month, "07");
    }
    else if(strcmp(token, "Aug") == 0)
    {
        strcpy(month, "08");
    }
    else if(strcmp(token, "Sep") == 0)
    {
        strcpy(month, "09");
    }
    else if(strcmp(token, "Oct") == 0)
    {
        strcpy(month, "10");
    }
    else if(strcmp(token, "Nov") == 0)
    {
        strcpy(month, "11");
    }
    else if(strcmp(token, "Dec") == 0)
    {
        strcpy(month, "12");
    }
    else
    {
        return NULL;
    }
    //returnVal *= 12;

    token = strtok(NULL, " ,");
    // assume next token is day
    dayNum = atoi(token);
    if(dayNum < 10)
    {
        day[0] = '0';
        day[1] = token[0];
        day[2] = 0;
    }
    else
    {
        strcpy(day, token);
    }

    // this should get to the next word (year) no matter how strtok ends up working...
    // if a bad string, we're at least saved from infinite loop
    do
    {
        token = strtok(NULL," ,");
    }while(token == NULL && tryCount++ < MAX_CONSECUTIVE_TOKENS);

    //assume it was year...
    if(tryCount <= MAX_CONSECUTIVE_TOKENS)
    {
        strcpy(returnVal, token);
        strcat(returnVal, "-");
        strcat(returnVal, month);
        strcat(returnVal, "-");
        strcat(returnVal, day);
        return returnVal;
    }
    else
    {
        free(returnVal);
        return NULL;
    }
}
